【朗報】Terraform v0.7.0 から既存リソースをインポートする機能が追加されます!
はじめに
こんにちは、中山です。
次回リリースバージョンであるTerraformのv0.7.0にはいろいろと大きな変更点があります。本エントリでは変更点の内インパクトの大きい import
サブコマンドについてご紹介します。
import
サブコマンドとは何か
ドキュメントから引用します。
Terraform is able to import existing infrastructure. This allows you take resources you've created by some other means and bring it under Terraform management.
つまりTerraform以外で作成したAWSなどのresourceをTerraform管理下にすることができる機能です。すばらしい。ただし、v.0.7.0時点では以下の文章に書かれているように tfstate
へのインポートのみ実装される予定です。
The current implementation of Terraform import can only import resources into the state. It does not generate configuration. A future version of Terraform will also generate configuration.
そのため import
サブコマンドで既存リソースをインポート後、自分で tf
ファイルを作成する必要があります。この辺りの改善は今後に期待しましょう。
従来のAWSリソースインポート事情
AWS provider限定ではありますが、以前からAWS resourceのインポートはterraformingを利用することにより可能でした。このツールはRuby製のツールで既存AWSリソースから tf
と tfstate
両方を生成することが可能です。つまり、v0.7.0の import
サブコマンドに対応していない機能も実装しています。そのため、しばらくは両方のツールが混在する状況になると思われます。
import
サブコマンドの使い方
それでは早速使ってみましょう。
コマンドの書式
以下の通りです。
terraform import [options] ADDR ID
ADDR
にresourceのAddressを指定します。 <resource-type>.<resource-name>
の形式で指定します。詳細はドキュメントを参照してください。 ID
にはresourceのIDを指定します。例えば、EC2インスタンスの場合はインスタンスIDのことです。
EC2インスタンスをインポートしてみる
東京リージョンに設置されているインスタンスID i-b41c682b
のEC2インスタンスをインポートしてみます。
$ terraform import aws_instance.bar i-b41c682b provider.aws.region The region where AWS operations will take place. Examples are us-east-1, us-west-2, etc. Default: us-east-1 Enter a value: ap-northeast-1 aws_instance.bar: Importing from ID "i-b41c682b"... aws_instance.bar: Import complete! Imported aws_instance (ID: i-b41c682b) aws_instance.bar: Refreshing state... (ID: i-b41c682b) Import success! The resources imported are shown above. These are now in your Terraform state. Import does not currently generate configuration, so you must do this next. If you do not create configuration for the above resources, then the next `terraform plan` will mark them for destruction.
コマンド実行後、カレントディレクトリに terraform.tfstate
というファイルが作成されます。中身を確認してみましょう。
$ cat terraform.tfstate { "version": 3, "terraform_version": "0.7.0", "serial": 0, "lineage": "f9822c82-fd5c-4eb2-86ce-08741d36e896", "modules": [ { "path": [ "root" ], "outputs": {}, "resources": { "aws_instance.bar": { "type": "aws_instance", "primary": { "id": "i-b41c682b", "attributes": { "ami": "ami-383c1956", <snip>
tfstate
ファイルが作成されているようですね。この状態で plan
サブコマンドを実行すると tf
ファイルが存在しないため、このresourceを削除する旨表示されてしまいます。このresource用の tf
ファイルを以下のように作成してみましょう。
<snip> variable "region" { default = "ap-northeast-1" } variable "web_instance_ami_id" { default = "ami-383c1956" } variable "web_instance_type" { default = "t2.micro" } provider "aws" { region = "${var.region}" } resource "aws_instance" "bar" { ami = "${var.web_instance_ami_id}" instance_type = "${var.web_instance_type}" vpc_security_group_ids = ["sg-f5522491"] subnet_id = "subnet-980ce0ee" key_name = "test" associate_public_ip_address = true root_block_device { volume_type = "gp2" volume_size = 8 } user_data = <<EOT #cloud-config repo_update: true repo_upgrade: all runcmd: - cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime EOT tags { Name = "simple" } }
plan
を実行してみます。
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_instance.bar: Refreshing state... (ID: i-b41c682b) The Terraform execution plan has been generated and is shown below. Resources are shown in alphabetical order for quick scanning. Green resources will be created (or destroyed and then created if an existing resource exists), yellow resources are being changed in-place, and red resources will be destroyed. Cyan entries are data sources to be read. Note: You didn't specify an "-out" parameter to save this plan, so when "apply" is called, Terraform can't guarantee this is what will execute. -/+ aws_instance.bar ami: "ami-383c1956" => "ami-383c1956" associate_public_ip_address: "" => "true" (forces new resource) availability_zone: "ap-northeast-1a" => "<computed>" ebs_block_device.#: "0" => "<computed>" ephemeral_block_device.#: "0" => "<computed>" instance_state: "running" => "<computed>" instance_type: "t2.micro" => "t2.micro" key_name: "test" => "test" placement_group: "" => "<computed>" private_dns: "ip-172-16-0-4.ap-northeast-1.compute.internal" => "<computed>" private_ip: "172.16.0.4" => "<computed>" public_dns: "ec2-54-238-193-249.ap-northeast-1.compute.amazonaws.com" => "<computed>" public_ip: "54.238.193.249" => "<computed>" root_block_device.#: "1" => "1" root_block_device.0.delete_on_termination: "true" => "true" root_block_device.0.iops: "100" => "<computed>" root_block_device.0.volume_size: "8" => "8" root_block_device.0.volume_type: "gp2" => "gp2" security_groups.#: "0" => "<computed>" source_dest_check: "true" => "true" subnet_id: "subnet-980ce0ee" => "subnet-980ce0ee" tags.%: "1" => "1" tags.Name: "simple" => "simple" tenancy: "default" => "<computed>" vpc_security_group_ids.#: "1" => "1" vpc_security_group_ids.156324148: "sg-f5522491" => "sg-f5522491" Plan: 1 to add, 0 to change, 1 to destroy.
ハイライトの箇所に注目していただきたいのですが、 associate_public_ip_address
の項目が "" => "true" (forces new resources)
と表示されています。つまり、 apply
実行時、既存resourceの再作成が発生してしまいます。また、 user_data
の項目も表示されていません。現時点では単純にインポートするだけでOKとはならないようです。残念。
state
サブコマンドを使う
tfstate
ファイルは単なるJSONなので、エディタなどを使い直接修正することも可能ですが、それは非推奨になっています。そこで、v0.7.0からstateサブコマンドが導入されます。このサブコマンドを利用することで tfstate
ファイルの修正が可能です。また、単にファイルを修正するだけではなく以下のような特徴があります。
- Unix系ツール(grep/awkなど)と連携しやすいように作られている
tfstate
のバックアップを自動で作成する
コマンドの書式
以下の通りです。
Usage: terraform state <subcommand> [options] [args]
このコマンドは更にサブコマンドを指定する形式になっています。現時点で対応しているコマンドは以下の通りです。
list
show
mv
それぞれのコマンドについてご紹介します。
list
list
サブコマンドは tfstate
ファイルからresource名を標準出力に表示します。コマンドの書式は以下の通りです。
terraform state list [options] [address...]
使用例は以下の通りです。
# 全てのresourceを表示 $ terraform state list <snip> aws_instance.bar # resource名でフィルタリング $ terraform state list aws_instance.bar aws_instance.bar
show
show
サブコマンドは1つのresource情報(attribute)を標準出力に表示します。コマンドの書式は以下の通りです。
terraform state show [options] ADDRESS
使用例は以下の通りです。
$ terraform state show aws_instance.bar id = i-b41c682b ami = ami-383c1956 availability_zone = ap-northeast-1a disable_api_termination = false ebs_block_device.# = 0 ebs_optimized = false ephemeral_block_device.# = 0 iam_instance_profile = instance_state = running instance_type = t2.micro key_name = test monitoring = false private_dns = ip-172-16-0-4.ap-northeast-1.compute.internal private_ip = 172.16.0.4 public_dns = ec2-54-238-193-249.ap-northeast-1.compute.amazonaws.com public_ip = 54.238.193.249 root_block_device.# = 1 root_block_device.0.delete_on_termination = true root_block_device.0.iops = 100 root_block_device.0.volume_size = 8 root_block_device.0.volume_type = gp2 security_groups.# = 0 source_dest_check = true subnet_id = subnet-980ce0ee tags.% = 1 tags.Name = simple tenancy = default vpc_security_group_ids.# = 1 vpc_security_group_ids.156324148 = sg-f5522491
mv
mv
サブコマンドは tfstate
の情報を変更できます。resource名の変更/module化/別 tfstate
ファイルへの移動、といった操作が可能です。コマンドの書式は以下の通りです。
terraform state mv [options] SOURCE DESTINATION
使用例は以下の通りです。 aws_vpc
resourceのresource名を変更してみます。
$ terraform state mv aws_vpc.vpc aws_vpc.test Moved aws_vpc.vpc to aws_vpc.test
mv
サブコマンドは自動で tfstate
ファイルをバックアップしてくれます。差分を確認してみましょう。
--- terraform.tfstate.1467891070..backup 2016-07-07 20:31:10.000000000 +0900 +++ terraform.tfstate 2016-07-07 20:31:10.000000000 +0900 @@ -1,7 +1,7 @@ { "version": 3, "terraform_version": "0.7.0", - "serial": 34, + "serial": 35, "modules": [ { "path": [ @@ -226,7 +226,7 @@ } } }, - "aws_vpc.vpc": { + "aws_vpc.test": { "type": "aws_vpc", "primary": { "id": "vpc-73575616",
aws_vpc
resource名を変更してくれているようです。また、シリアル番号も変更されるので tf
ファイルを更新すれば、実際の状態と tfstate
の状態が合致するようになっています。
tf
ファイルを手動で変更後 plan
を実行してみましょう。
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_key_pair.site_key: Refreshing state... (ID: test) aws_vpc.test: Refreshing state... (ID: vpc-73575616) aws_internet_gateway.public: Refreshing state... (ID: igw-ea6c098f) aws_security_group.web: Refreshing state... (ID: sg-db6d21bf) aws_subnet.public: Refreshing state... (ID: subnet-e56b9893) aws_route_table.public: Refreshing state... (ID: rtb-f730c693) aws_instance.web: Refreshing state... (ID: i-f3feb86c) aws_network_acl.acl: Refreshing state... (ID: acl-a77b97c3) aws_route_table_association.public: Refreshing state... (ID: rtbassoc-e3d35487) No changes. Infrastructure is up-to-date. This means that Terraform could not detect any differences between your configuration and the real physical resources that exist. As a result, Terraform doesn't need to do anything.
aws_vpc
のresource名が変更されていること、差分が解消されていることが確認できます。やりましたね。
まとめ
いかがだったでしょうか。
import
サブコマンドの導入によりTerraformの可能性がまた1つ広がりました。まだまだ基本的な機能しか実装されていませんが、今後の更新が楽しみです。
本エントリがみなさんの参考になれば幸いです。